package Servidor;

import Conexion.SerializedObject;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;


/**
 * Esta clase representa el socket en el lado del servidor con el que se comunicara
 * con el cliente.
 * Contiene un entero numThread que almacenara el numero del Thread que indica 
 * la posición de la lista conexiones al servidor que ocupa.
 * Contiene una variable booleana que indica el momento en que finalizará el hilo
 * basico de recepcion de conexiones
 * Contiene una instancia de la clase AdminPartidas quien almacenará las partidas
 * creadas
 * Contiene un flujo de salida de objetos serializados oos que permite enviar
 * objetos serializados a traves del flujo de salida del socket.
 * Contiene un flujo de entrada de objets serializados ois que permite leer
 * objetos serializados a traves del flujo de entrada del socket.
 * Contiene un socket que permite mantener la conexion entre la maquina cliente
 * y el servidor via Tcp/ip.
 * Contiene un nombre que india el nombre del cliente a quien representa este socket
 * de comunicación.
 *
 */
public class ServidorThread extends Thread{
    private int numThread=0;
    private boolean fin=false;
    private AdminPartidas ADMON;
    private ObjectOutputStream oos = null;
    private ObjectInputStream ois = null;
    private Socket socket=null;
    private String nombre=null;

    /**
     * retorna el Nombre de cliente a quien va dirigida la comunicación de este
     * socket
     * @return String
     * nombre del cliente a quien va dirigida esta comunicación
     */
    public String getNombre() {
        return nombre;
    }

    /**
     * Modifica el nombre del cliente de este socket
     * @param nombre
     * valor del nombre del cliente de ese socket
     */
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    /**
     * este metodo devuelve el numero de conexion de ese socket es decir el puesto que ocupa
     * en la lista de conexione de cliente en el servidor
     * @return int
     * retorna el numero de conexión de este socket
     */
    public int getNumThread() {
        return numThread;
    }

    /**
     * Permite modificar el numero de conexión de ese socket
     * @param numThread int
     * valor del numero de conexion de este socket.
     */
    public void setNumThread(int numThread) {
        this.numThread = numThread;
    }



    /**
     * Precondicion: El cliente mantiene su conexión al servidor y una instancia
     * de AdminPartidas ya ha sido creada
     * Postcondición: SE han creado con exito los flujos del socket de entrada y
     * salida. Se instancio con exito AdminPartidas.
     * Este metodo establece una conexión con el cliente que acaba de conectarse
     * al servidor e inicializa los flujo de entrada y salida del socket
     * @param socket Socket
     * Socket que permitira comunicarse con el cliente.
     * @param M AdminPartidas
     * Instancia de AdminPartidas que hara uso de los servicios de AdminPartidas
     */
    public ServidorThread(Socket socket, AdminPartidas M) {
            super("ServidorThread");
            this.socket = socket;
            try {
                oos = new ObjectOutputStream(socket.getOutputStream());
                ois = new ObjectInputStream(socket.getInputStream());
            } catch (IOException ex) {
                Logger.getLogger(ServidorThread.class.getName()).log(Level.SEVERE, null, ex);
            }
            ADMON=M;   
    }

     /**
     * hilo de ejecución que permite mantener la comunicación con el cliente justo
     * hasta que termina la  inscripción en una partida por parte de un cliente.
     */
    @Override
    @SuppressWarnings("empty-statement")
    public void run(){
        try {
                
                while(!fin){
                    SerializedObject os1= new SerializedObject();
                    SerializedObject os2= null;
                    os2=this.recibir();
                    String temp=null;
                    //System.out.println(os2.getTipoM());

                    switch(Integer.parseInt(os2.getTipoM())){
                        case -1:break;
                        case 0: fin=true;
                                this.close();
                                break;
                        case 1: temp=ADMON.getPartidas()+"";
                                os1.setMensaje(temp);
                                this.enviar(os1);
                                break;
                        case 2: temp=ADMON.selectPartidas(Integer.parseInt(os2.getMensaje())-1,this.numThread);
                                this.setNombre(os2.getName());
                                os1.setMensaje(temp);
                                this.enviar(os1);
                                break;
                        case 3: System.out.println("HOLA");
                                ADMON.actualizarJugPartida(Integer.parseInt(os2.getMensaje())-1);
                                fin=true;
                                break;

                        case 5: break;
                    }   
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
    }

        /**
         * Este metodo permite enviar un objeto serializado por medio del socket
         * creado en esta clase.
         * @param so SerializedObject
         * Objeto serializado que sera envia por el socket.
         */
    public void enviar(SerializedObject so){
            try{
                // write the objects to the server
                oos.writeObject(so);
                oos.flush();
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        /**
         * Este metodo permite recibir un objeto serializado a traves del socket
         * de este objeto.
         * Precondición el objeto a recibir es serializado.
         * @return SerializedObject
         * devuelve el objeto serializado recibido por el socket conectado al
         * servidor.
         */
        public SerializedObject recibir(){
                SerializedObject result = null;
            try{
                // read an object from the server
                result = (SerializedObject) ois.readObject();
            }catch(Exception e){
                e.printStackTrace();
            }
            return result;
        }

        /**
         * Este metodo permite cerrar las conexiones del socket creadas.
         */
        public void close(){
           try {
                oos.close();
                ois.close();
                socket.close();
           }catch(Exception e){
                System.out.println(e.getMessage());
           }
        }

}
